﻿using Microsoft.Win32;
using System;
using System.IO;

namespace CXW.Core
{
    /// <summary></summary>
    public static partial class FileUtility
    {
        readonly static char[] separators = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, Path.VolumeSeparatorChar };
        static string applicationRootPath = AppDomain.CurrentDomain.BaseDirectory;
        const string fileNameRegEx = @"^([a-zA-Z]:)?[^:]+$";

        public static string ApplicationRootPath
        {
            get
            {
                return applicationRootPath;
            }
            set
            {
                applicationRootPath = value;
            }
        }

        static string GetPathFromRegistry(string key, string valueName)
        {
            using (RegistryKey installRootKey = Registry.LocalMachine.OpenSubKey(key))
            {
                if (installRootKey != null)
                {
                    object o = installRootKey.GetValue(valueName);
                    if (o != null)
                    {
                        string r = o.ToString();
                        if (!string.IsNullOrEmpty(r))
                            return r;
                    }
                }
            }
            return null;
        }

        static string GetPathFromRegistryX86(string key, string valueName)
        {
            using (RegistryKey baseKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
            {
                using (RegistryKey installRootKey = baseKey.OpenSubKey(key))
                {
                    if (installRootKey != null)
                    {
                        object o = installRootKey.GetValue(valueName);
                        if (o != null)
                        {
                            string r = o.ToString();
                            if (!string.IsNullOrEmpty(r))
                                return r;
                        }
                    }
                }
            }
            return null;
        }
        #region InstallRoot Properties



        static string netSdk20InstallRoot = null;
        /// <summary>
        /// Location of the .NET 2.0 SDK install root.
        /// </summary>
        public static string NetSdk20InstallRoot
        {
            get
            {
                if (netSdk20InstallRoot == null)
                {
                    netSdk20InstallRoot = GetPathFromRegistry(@"SOFTWARE\Microsoft\.NETFramework", "sdkInstallRootv2.0") ?? string.Empty;
                }
                return netSdk20InstallRoot;
            }
        }

        static string windowsSdk60InstallRoot = null;
        /// <summary>
        /// Location of the .NET 3.0 SDK (Windows SDK 6.0) install root.
        /// </summary>
        public static string WindowsSdk60InstallRoot
        {
            get
            {
                if (windowsSdk60InstallRoot == null)
                {
                    windowsSdk60InstallRoot = GetPathFromRegistry(@"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0", "InstallationFolder") ?? string.Empty;
                }
                return windowsSdk60InstallRoot;
            }
        }

        static string windowsSdk60aInstallRoot = null;
        /// <summary>
        /// Location of the Windows SDK Components in Visual Studio 2008 (.NET 3.5; Windows SDK 6.0a).
        /// </summary>
        public static string WindowsSdk60aInstallRoot
        {
            get
            {
                if (windowsSdk60aInstallRoot == null)
                {
                    windowsSdk60aInstallRoot = GetPathFromRegistry(@"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0a", "InstallationFolder") ?? string.Empty;
                }
                return windowsSdk60aInstallRoot;
            }
        }

        static string windowsSdk61InstallRoot = null;
        /// <summary>
        /// Location of the .NET 3.5 SDK (Windows SDK 6.1) install root.
        /// </summary>
        public static string WindowsSdk61InstallRoot
        {
            get
            {
                if (windowsSdk61InstallRoot == null)
                {
                    windowsSdk61InstallRoot = GetPathFromRegistry(@"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.1", "InstallationFolder") ?? string.Empty;
                }
                return windowsSdk61InstallRoot;
            }
        }

        static string windowsSdk70InstallRoot = null;
        /// <summary>
        /// Location of the .NET 3.5 SP1 SDK (Windows SDK 7.0) install root.
        /// </summary>
        public static string WindowsSdk70InstallRoot
        {
            get
            {
                if (windowsSdk70InstallRoot == null)
                {
                    windowsSdk70InstallRoot = GetPathFromRegistry(@"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0", "InstallationFolder") ?? string.Empty;
                }
                return windowsSdk70InstallRoot;
            }
        }

        static string windowsSdk71InstallRoot = null;
        /// <summary>
        /// Location of the .NET 4.0 SDK (Windows SDK 7.1) install root.
        /// </summary>
        public static string WindowsSdk71InstallRoot
        {
            get
            {
                if (windowsSdk71InstallRoot == null)
                {
                    windowsSdk71InstallRoot = GetPathFromRegistry(@"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1", "InstallationFolder") ?? string.Empty;
                }
                return windowsSdk71InstallRoot;
            }
        }

        static string windowsSdk80InstallRoot = null;
        /// <summary>
        /// Location of the .NET 4.5 SDK (Windows SDK 8.0) install root.
        /// </summary>
        public static string WindowsSdk80NetFxTools
        {
            get
            {
                if (windowsSdk80InstallRoot == null)
                {
                    windowsSdk80InstallRoot = GetPathFromRegistryX86(@"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools", "InstallationFolder") ?? string.Empty;
                }
                return windowsSdk80InstallRoot;
            }
        }
        #endregion


        /// <summary>
        /// Searches all the .net sdk bin folders and return the path of the
        /// exe from the latest sdk.
        /// </summary>
        /// <param name="exeName">The EXE to search for.</param>
        /// <returns>The path of the executable, or null if the exe is not found.</returns>
        public static string GetSdkPath(string exeName)
        {
            string execPath;
            if (!string.IsNullOrEmpty(WindowsSdk80NetFxTools))
            {
                execPath = Path.Combine(WindowsSdk80NetFxTools, exeName);
                if (File.Exists(execPath)) { return execPath; }
            }
            if (!string.IsNullOrEmpty(WindowsSdk71InstallRoot))
            {
                execPath = Path.Combine(WindowsSdk71InstallRoot, "bin\\" + exeName);
                if (File.Exists(execPath)) { return execPath; }
            }
            if (!string.IsNullOrEmpty(WindowsSdk70InstallRoot))
            {
                execPath = Path.Combine(WindowsSdk70InstallRoot, "bin\\" + exeName);
                if (File.Exists(execPath)) { return execPath; }
            }
            if (!string.IsNullOrEmpty(WindowsSdk61InstallRoot))
            {
                execPath = Path.Combine(WindowsSdk61InstallRoot, "bin\\" + exeName);
                if (File.Exists(execPath)) { return execPath; }
            }
            if (!string.IsNullOrEmpty(WindowsSdk60aInstallRoot))
            {
                execPath = Path.Combine(WindowsSdk60aInstallRoot, "bin\\" + exeName);
                if (File.Exists(execPath)) { return execPath; }
            }
            if (!string.IsNullOrEmpty(WindowsSdk60InstallRoot))
            {
                execPath = Path.Combine(WindowsSdk60InstallRoot, "bin\\" + exeName);
                if (File.Exists(execPath)) { return execPath; }
            }
            if (!string.IsNullOrEmpty(NetSdk20InstallRoot))
            {
                execPath = Path.Combine(NetSdk20InstallRoot, "bin\\" + exeName);
                if (File.Exists(execPath)) { return execPath; }
            }
            return null;
        }

        /// <summary>深度复制文件</summary>
        /// <param name="sourceDirectory">要复制的目录</param>
        /// <param name="destDirectory">目标目录</param>
        /// <param name="overwrite">如果可以覆盖目标文件，则为 true；否则为 false。</param>
        public static void DeepCopy(string sourceDirectory, string destDirectory, bool overwrite)
        {
            if (!Directory.Exists(destDirectory))
            {
                Directory.CreateDirectory(destDirectory);
            }
            foreach (string fileName in Directory.GetFiles(sourceDirectory))
            {
                File.Copy(fileName, Path.Combine(destDirectory, Path.GetFileName(fileName)), overwrite);
            }
            foreach (string directoryName in Directory.GetDirectories(sourceDirectory))
            {
                DeepCopy(directoryName, Path.Combine(destDirectory, Path.GetFileName(directoryName)), overwrite);
            }
        }


        //TODO This code is Windows specific
        static bool MatchN(string src, int srcidx, string pattern, int patidx)
        {
            int patlen = pattern.Length;
            int srclen = src.Length;
            char next_char;

            for (;;)
            {
                if (patidx == patlen)
                    return (srcidx == srclen);
                next_char = pattern[patidx++];
                if (next_char == '?')
                {
                    if (srcidx == src.Length)
                        return false;
                    srcidx++;
                }
                else if (next_char != '*')
                {
                    if ((srcidx == src.Length) || (src[srcidx] != next_char))
                        return false;
                    srcidx++;
                }
                else
                {
                    if (patidx == pattern.Length)
                        return true;
                    while (srcidx < srclen)
                    {
                        if (MatchN(src, srcidx, pattern, patidx))
                            return true;
                        srcidx++;
                    }
                    return false;
                }
            }
        }
    }
}